package com.gq.webstore.hdzw;

import cn.hutool.core.codec.Base62;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.MD5;
import cn.hutool.http.HttpConnection;
import com.gq.webstore.hdzw.model.Chapter;
import com.gq.webstore.hdzw.model.Store;
import com.gq.webstore.hdzw.util.ContentUtil;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Main {
    private static final String DEFAULT_TMP_CHARSET = "UTF-8";
    private static final String TMP_CHAPTER_PAHT = "./tmp_c";
    private static final String TMP_STORE_PAHT = "./tmp_s";
    private static final long SLEEP_TIME = 100;
    private static final List<String> needRemoveSet = Arrays.asList(
            "本章&#x6CA1;完，请点击下&#8212;页继续阅读！如果被&#x8F6C;&#x7801;了请退出&#x8F6C;&#x7801;或者更换浏揽&#x5668;即可。",
            "田隶提醒您：看完记得收藏【洪都中文网】 m.hdzww.com，下次我更新您才方便继续阅读哦，期待精彩继续！",
            "温馨提示：亲爱的读者，如果你觉得本站还好，为了避免丢失和转马，请勿依赖搜索访问，建议你使用[华为刘揽器]或[Firefox火狐刘揽器]访问并收蔵【洪都中文网】 m.hdzww.com。我们将会持续为你更新，还建议你注册会员使用书架功能追书阅读更方便。",
            "浓墨浇书提醒您：看完记得收藏【洪都中文网】 m.hdzww.com，下次我更新您才方便继续阅读哦，期待精彩继续！"
    );

    public static void main(String[] args) throws Exception {
        //https://m.hdzww.com/hd/2583288755/
        //https://m.hdzww.com/hd/2538931924/
//        Map<String,String> cookieMap=cookie(
//                "MUserName=gqgq0311; nsbszddll=2815d905b061e89c; Mpsw=12%2A%2A%2A%2A%2A3; MUID=125176; Hm_lvt_2b08a0d870fa35494eed8f9dcd605967=1747647803; ASPSESSIONIDCCBSTRTC=JCEKBIKCBGGIBIEJHMCANEKJ; ASPSESSIONIDAAASQRTD=JNMMBIKCAMMAOKMOAFFHHOEG; ASPSESSIONIDCACRRTRC=JPIBDIKCAKGLDFDFNNPEGNMN; ASPSESSIONIDQABQSTQA=DCBEDIKCBPNMFBBEOFBKCPKH; ASPSESSIONIDAACTRRRC=MHBIGNEAIAILHIJEDIBLPKNJ; ASPSESSIONIDCCDTRQSD=JMJKGNEAMDJNNMLKLPCBPHJD; ASPSESSIONIDSCBQSQRA=GFMCINEAIAEKIFGBFNMBHGMD; ASPSESSIONIDAABQSRQC=JAGDDIKCACNOLKCFPGDFGBBN; ASPSESSIONIDSCCQQTQA=MONKBIKCGFCBCNOJOCKAJIBI; ASPSESSIONIDAADRTTRD=EEBKBIKCNCPNNFPEDLGCMFEA; ASPSESSIONIDSACRQRRA=JDEDDIKCAOLJOLIFKBMHPJIN; ASPSESSIONIDACCTTSQC=NIMFDIKCJPPGDKENDONHHKCE; ASPSESSIONIDAABCCABC=KLBGMOKAGJFIHILKOEPEFKJA; ASPSESSIONIDACBAADDD=ANAMHOKANDDHPGABIJPIILDG; ASPSESSIONIDAABBABCD=AEFLHOKABDAPHFAPGHPNDHBK; ASPSESSIONIDACCABBAC=DDKFMOKABMKBLNJEHNNBDBNJ; ASPSESSIONIDCCDCDACC=BJCAHOKAOLHBLJBFNKNJBKEA; qnzbcnmcb=9a5b54b1530491ba; ASPSESSIONIDCADCBBDC=KAHAHOKAEDNGFOCLNBOGGBCA; ASPSESSIONIDCACCAABD=MOIGNOKAFFDPEFPDNLJFNNAK; nxgmnmry=7c527358791a28e2; ASPSESSIONIDCCDBBCCC=NELPGOKAFOGGKDGGEHEJPLFN; fscwbgjz=9eedda25a76225f3"
//        );
        Map<String,String> cookieMap=map(
                "nxgmnmry","aab135a481a505b0",
                "nsbszddll","2815d905b061e89c",
                "fscwbgjz","23cf7f7e3b2afc28",
                "qnzbcnmcb","65bdadb3c7cf505a"
        );
        Map<String,String> headerMap=map(
                "User-Agent","Mozilla/5.0 (iPhone; CPU iPhone OS 5_0 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A334 Safari/7534.48.3",
                "Referer","https://m.hdzww.com/hd/2549179949/"
        );
        loadStore("https://m.hdzww.com/hd/2549179949/", null, cookieMap,headerMap, 0);
    }

    private static void loadStore(String url, String name, Map<String, String> cookie,Map<String,String> header, int idx) throws Exception {
        new File(TMP_CHAPTER_PAHT + "/a.txt").getParentFile().mkdirs();
        new File(TMP_STORE_PAHT + "/a.txt").getParentFile().mkdirs();

        Context context = new Context();
        context.setMainUrl(url);
        context.setCookie(cookie);
        context.setHeader(header);
        context.setCharset("GBK");
        Store store = new Store();
        store.setUrl(url);
        store.setName(name == null ? "UNKNOWN" : name);

        String fileKey = (name == null ? "0000" : name) + "_" + md5(url);
        File muluFile = new File(TMP_CHAPTER_PAHT + "/" + fileKey);
        System.out.println("目录 key=" + fileKey + ",url=" + url);
        String orgContent = doGet(url, context);
        FileUtil.writeString(orgContent, muluFile, DEFAULT_TMP_CHARSET);
        store.setOrgContent(orgContent);
        String title = ContentUtil.cutFromFirst(orgContent, "<meta property=\"og:title\" content=\"", "\" />");
        if (name == null || name.isEmpty()) {
            store.setName(title);
            File newMuLuFile = new File(TMP_CHAPTER_PAHT + "/" + title + "_目录.txt");
            muluFile.renameTo(newMuLuFile);
            System.out.println("目录 rename=" + newMuLuFile.getName());
        } else {
            title = name;
        }
        context.setTempPath(TMP_CHAPTER_PAHT + "/" + title + "/");
        new File(context.getTempPath() + "a.txt").getParentFile().mkdirs();

        System.out.println("获得目录 title=" + title + ",url=" + url);

        String catalogue = ContentUtil.cutFromFirst(orgContent, "<ul class=\"MLlist\">", "</ul>");
        String arr[] = catalogue.split("</a></li>");
        store.setOrgChapterSize(arr.length - 1);
        for (int i = idx; i < arr.length; i++) {
            String c = arr[i];
            if (!c.contains("<a href=\"")) {
                if (i == arr.length - 1) {
                    break;
                } else {
                    throw new RuntimeException("解析章节错误,i=" + i + ",c=" + c);
                }
            }
            String cTitle = ContentUtil.cutFromFirst(c, "\">", "");
            String cUrl = ContentUtil.cutFromFirst(c, "<a href=\"", "\">");
            Chapter chapter = new Chapter();
            chapter.setName(cTitle);
            chapter.setIdx(i + 1);
            if (cUrl.startsWith("/")) {
                cUrl = getDomain(url) + cUrl;
            } else {
                cUrl = getCurPath(url) + "/" + cUrl;
            }
            chapter.setUrl(cUrl);
            store.getChapterList().add(chapter);
        }

        for (Chapter chapter : store.getChapterList()) {
            loadCh(chapter, chapter.getUrl(), context, 0);
            if (chapter.isNotComplete()) {
                store.getPreLines().add(chapter.getName());
            }
        }
        String storeContent = getContent(context, store);
        String fileName = getValidFileName(title) + ".txt";
        FileUtil.writeString(storeContent, new File(TMP_STORE_PAHT + "/" + fileName), context.getCharset());
        System.out.println(fileName + " is over,size=" + storeContent.length());
        if (!store.getPreLines().isEmpty()) {
            System.out.println(fileName + " 未完章节数量:" + store.getPreLines().size() + "个");
        }
    }

    private static void loadCh(Chapter chapter, String url, Context context, int pageNum) throws Exception {
        String key = getLenStr(chapter.getIdx(), 4) + "_" + getLenStr(pageNum, 2) + "_" + getValidFileName(chapter.getName());

        String fileKey = key + "_" + md5(url);
        String orgContent = load(url, context, fileKey + ".txt");

//        Document doc= Jsoup.parse(orgContent);
//        System.out.println(doc);
        String content = ContentUtil.cutFromFirst(orgContent, "<div class=\"TxtContent\">", "</div>");
        content = content.replaceAll("</p><p>", "\n");
        content = trimNotSeeChar(content);
        int startIdx1 = content.indexOf("<p>");
        int startIdx2 = content.indexOf("<br>");
        int startIdx3 = content.indexOf("<br/>");
        int startIdx4 = content.indexOf("<br />");
        int startIdx = getValidMinIdx(startIdx1, startIdx2, startIdx3, startIdx4);
        if (startIdx < 0) {
            throw new RuntimeException("error ,key=" + key);
        }

        int endIdx = content.lastIndexOf("本章&#x6CA1;完");
        if (endIdx < 0) {
            endIdx = content.lastIndexOf("</p>");
        }
        if (endIdx < 0) {
            endIdx = content.lastIndexOf("<br />");
        }
        if (endIdx < 0) {
            endIdx = content.lastIndexOf("<br/>");
        }
        if (endIdx < 0) {
            endIdx = content.lastIndexOf("<br>");
        }
        if (endIdx < 0) {
            endIdx = content.lastIndexOf("</br>");
        }
        if (endIdx < 0) {
            endIdx = content.lastIndexOf("</ br>");
        }
        if (endIdx < 0) {
            endIdx = content.length();
        }
        startIdx = 0;//TODO 获取信息数据
        content = content.substring(startIdx, endIdx);
        content = content.replaceAll("<p>", "\n");
        content = content.replaceAll("</p>", "\n");
        content = content.replaceAll("<br />", "\n");
        content = content.replaceAll("<br/>", "\n");
        content = content.replaceAll("<br>", "\n");
        content = content.replaceAll("</br>", "\n");
        content = content.replaceAll("\r", "");

        for (String tmp : needRemoveSet) {
            content = content.replace(tmp, "");
        }
        String zuozhetixing = "提醒您：看完记得收藏【洪都中文网】 m.hdzww.com，下次我更新您才方便继续阅读哦，期待精彩继续！";
        if (content.endsWith(zuozhetixing)) {
            int lastIdx1 = content.lastIndexOf("\n　　");
            if (lastIdx1 < 0) {
                lastIdx1 = content.lastIndexOf("\n  ");
            }
            int p = content.length() - lastIdx1 - zuozhetixing.length();
            if (lastIdx1 > 0 && p < 15) {
                content = content.substring(0, lastIdx1);
            }
        }

        StringBuilder builder = new StringBuilder(content.length() + 2);//TODO替换空行
        BufferedReader reader = new BufferedReader(new StringReader(content));
        String line = null;
        while ((line = reader.readLine()) != null) {
            line = trimNotSeeChar(line);
            if (StrUtil.isBlankIfStr(line) || "\"".equals(line) || "＂".equals(line)) {
                continue;
            }
            builder.append("　　");
            builder.append(line);
            builder.append("\n");
        }
        for (int i = builder.length() - 1; i >= 0; i--) {
            char c = builder.charAt(i);
            if (c == '\n') {
                builder.deleteCharAt(i);
            } else {
                break;
            }
        }
        content = builder.toString();
        int i = 0;
        while (content.contains("\n\n\n")) {
            content = content.replaceAll("\n\n\n", "\n\n");
            i++;
            if (i > 20) {
                break;
            }
        }

//        content = ContentUtil.cutFromFirst(content, "<p>", "</p>", false);
//        int idx = content.indexOf("<br />");
//        if (idx > 0) {
//            content = content.substring(0, idx);
//        }

        //TODO 设置未完章节还在手打的信息
        FileUtil.writeString(content, new File(context.getTempPath() + key + ".txt"), DEFAULT_TMP_CHARSET);
        String pageStart = "<div id=\"PageSet\"";
        chapter.appendPage(url, content, orgContent);
        if (content.contains("正在手打中……努力更新中……")) {
            chapter.setNotComplete(true);
            System.out.println("****章节未完成*** 章节:" + chapter.getName());
        }
        if (!orgContent.contains(pageStart)) {
            return;
        }
        String page = ContentUtil.cutFromFirst(orgContent, pageStart, "</div>");
        String pages[] = page.split("</a>");
        String last = pages[pages.length - 1];
        if (!last.contains("<a href=\"")) {
            return;
        }
        String lastUrl = ContentUtil.cutFromFirst(last, "<a href=\"", "\"");
        if (url.endsWith(lastUrl)) {
            return;
        }
        lastUrl = getCurPath(url) + "/" + lastUrl;
        loadCh(chapter, lastUrl, context, pageNum + 1);
    }

    private static String trimNotSeeChar(String content) {
        int startIdx = 0;
        for (; startIdx < content.length(); startIdx++) {
            char c = content.charAt(startIdx);
            if (c == ' ' || c == '\n' || c == '\t' || c == '\r' || c == '　') {

            } else {
                break;
            }
        }
        int endIdx = content.length() - 1;
        for (; endIdx > startIdx; endIdx--) {
            char c = content.charAt(endIdx);
            if (c == ' ' || c == '\n' || c == '\t' || c == '\r' || c == '　') {

            } else {
                break;
            }
        }
        return content.substring(startIdx, endIdx + 1);
    }

    private static int getValidMinIdx(int... idxs) {
        int idx = -1;
        for (int i : idxs) {
            if (i >= 0) {
                if (idx < 0 || i < idx) {
                    idx = i;
                }
            }
        }
        return idx;
    }

    private static int getValidMaxIdx(int... idxs) {
        int idx = -1;
        for (int i : idxs) {
            if (i >= 0) {
                if (i > idx) {
                    idx = i;
                }
            }
        }
        return idx;
    }

    private static String getValidFileName(String name) {
        StringBuilder builder = new StringBuilder(name.length());
        for (int i = 0; i < name.length(); i++) {
            char c = name.charAt(i);
            if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c > 255 || "[]{}@#&()_-".contains(c + "")) {
                builder.append(c);
            } else {
                builder.append(" ");
            }
        }
        return builder.toString();
    }

    private static String getLenStr(Object obj, int i) {
        String str = String.valueOf(obj);
        if (str.length() >= i) {
            return str;
        }
        StringBuilder builder = new StringBuilder(i);

        while (builder.length() + str.length() < i) {
            builder.append("0");
        }
        builder.append(str);
        return builder.toString();
    }

    private static String getDomain(String url) {
        int idx = url.indexOf("://");
        if (idx < 0) {
            throw new RuntimeException("can not find domain,url=" + url);
        }
        int start = idx + 3;
        int end = url.indexOf("/", start);
        if (end < 0) {
            return url;
        }
        return url.substring(0, end);
    }


    private static String getCurPath(String url) {
        int end = url.lastIndexOf("/");
        if (end < 0) {
            return url;
        }
        return url.substring(0, end);
    }

    private static String load(String url, Context context, String fileName) throws Exception {
        String str;
        File file = new File(context.getTempPath() + fileName);
        if (file.exists()) {
            System.out.println("缓存 key=" + file.getName() + ",url=" + url);
            str = FileUtil.readString(file, DEFAULT_TMP_CHARSET);
            return str;
        }
        Thread.sleep(SLEEP_TIME);
        System.out.println("下载 key=" + file.getName() + ",url=" + url);
        str = doGet(url, context);
        FileUtil.writeString(str, file, DEFAULT_TMP_CHARSET);
        return str;
    }

    private static String doGet(String url, Context context) throws IOException {
        HttpConnection connection = new HttpConnection(url(url), null);
        if (context != null && context.getHeader() != null) {
            for (Map.Entry<String, String> entry : context.getHeader().entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue();
                if (StrUtil.isNotEmpty(key)) {
                    if (value == null) {
                        value = "";
                    }
                    connection.header(key, value, false);
                }
            }
        }
        if (context != null && context.getCookie() != null) {
            for (Map.Entry<String, String> entry : context.getCookie().entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue();
                if (StrUtil.isNotEmpty(key)) {
                    if (value == null) {
                        value = "";
                    }
                    connection.setCookie(key + "=" + value);
                }
            }
        }
        if (connection.responseCode() != 200) {
            throw new RuntimeException("code=" + connection.responseCode());
        }
        InputStream is = connection.getInputStream();
        String str = IoUtil.read(is, context.charsetOrUTF8());

        return str;
    }

    private static URL url(String url) {
        try {
            return new URL(url);
        } catch (MalformedURLException e) {
            throw new RuntimeException(e);
        }
    }

    private static String getContent(Context context, Store store) {
        StringBuilder builder = new StringBuilder(1500 * 1000);
        builder.append(store.getName()).append("\n\n");
        builder.append("章节共计:")
                .append(store.getChapterList().size()).append("/").append(store.getOrgChapterSize())
                .append("    字数:").append(store.getCharLen()).append("\n\n");
        if (!store.getPreLines().isEmpty()) {
            builder.append("未完章节:").append(store.getPreLines().size()).append("个,列表:").append("\n");
            for (String str : store.getPreLines()) {
                builder.append(" --:").append(str);
                builder.append("\n");
            }
        }
        builder.append("\n    ----<正文>----\n\n");
        for (Chapter c : store.getChapterList()) {
            builder.append(c.getName()).append("\n\n");
            builder.append(c.getContent());
            builder.append("\n");
            if (getLastChar(c.getContent()) != '\n') {
                builder.append("\n");
            }
        }
        return builder.toString();
    }

    private static char getLastChar(StringBuilder content) {
        if (content != null && content.length() > 0) {
            return content.charAt(content.length() - 1);
        }
        return 0;
    }

    private static Map<String, String> map(String... arr) {
        Map<String, String> map = new HashMap<>(arr.length / 2);
        for (int i = 0; i < arr.length; i += 2) {
            String key = arr[i];
            String val = null;
            if (i + 1 < arr.length) {
                val = arr[i + 1];
            }
            map.put(key, val);
        }
        return map;
    }

    private static String md5(String url) {
        return Base62.encode(MD5.create().digest(url, "utf-8"));
    }

    //    "MUserName=gqgq0311; nsbszddll=2815d905b061e89c; qnzbcnmcb=4ce800d43ca9ff9a; nxgmnmry=15510d6d57124425; fscwbgjz=92c22e6cac4eeba0; ASPSESSIONIDSACRQRRA=EIOCLDKCPMDAEBEMLAGHMJIM; ASPSESSIONIDQABQSTQA=CPCDLDKCIKLPHIBEPMCENEKI; ASPSESSIONIDACCTTSQC=FGIFLDKCEBOGEMPFJOKHAEHN; ASPSESSIONIDAADRTTRD=DLDIJDKCAKPFDNBPCIBIJBIM; Mpsw=12%2A%2A%2A%2A%2A3; MUID=125176; ASPSESSIONIDSCCQQTQA=NIEKJDKCAJOCKDEFLEOKBBPH; ASPSESSIONIDSCBQSQRA=BJHDAJEACOLDAAMCINFMPBJH; ASPSESSIONIDAABQSRQC=FIAELDKCHDGNKJFBJHFDLEDM; ASPSESSIONIDCCBSTRTC=EECLJDKCAIDKDMKEDCBKNGJH; Hm_lvt_2b08a0d870fa35494eed8f9dcd605967=1747647803; Hm_lpvt_2b08a0d870fa35494eed8f9dcd605967=1747654277";
    private static Map<String, String> cookie(String msg) {
        if (msg == null) {
            return new HashMap<>();
        }
        msg = msg.trim();
        if (msg.isEmpty()) {
            return new HashMap<>();
        }
        Map<String, String> map = new HashMap<>();
        String arr[] = msg.split(";");
        for (String str : arr) {
            String[] ttt = str.split("=");
            if (ttt.length == 2) {
                map.put(ttt[0].trim(), ttt[1].trim());
            }
        }
        return map;
    }
}
